//
// Created by kode.zhong on 2021/3/14.
//

#include <cstdint>
#include <iostream>

#include "compiler.h"

namespace lox {

constexpr size_t INVALID_LINE = UINT64_MAX;

void Compiler::Compile(const std::string &source) {
  Scanner scanner{source};
  size_t line = INVALID_LINE;
  for (;;) {
    Token token = scanner.ScanToken();
    if (token.line != line) {
      printf("%4d ", token.line);
      line = token.line;
    } else {
      printf("   | ");
    }
    printf("%2d '%s'\n", token.type, token.lexme.c_str());
    if (token.type == TOKEN_EOF) break;
  }
}


void Compiler::Advance(Scanner& scanner) {
  m_parser.previous = m_parser.current;
  for (;;) {
    m_parser.current = scanner.ScanToken();
    if (m_parser.current.type != TOKEN_ERROR) break;
    ErrorAtCurrent(m_parser.current.lexme);
  }
}

void Compiler::Consume(Scanner &scanner, TokenType type, const std::string &msg) {
  if (m_parser.current.type == type) {
    Advance(scanner);
    return;
  }
  ErrorAtCurrent(msg);
}

void Compiler::ErrorAtCurrent(const std::string &msg) {
  ErrorAt(m_parser.current, msg);

}

void Compiler::Error(const std::string &msg) {
  ErrorAt(m_parser.previous, msg);
}

void Compiler::ErrorAt(Token &token, const std::string &msg) {
  // Just return while the panic mode is set.
  if (m_parser.panic_mode) return;
  m_parser.panic_mode = true;
  std::cerr << "[line " << token.line << "] Error";
  if (token.type == TOKEN_EOF) {
    std::cerr << " at end";
  } else if (token.type == TOKEN_ERROR) {
    // Nothing
  } else{
    std::cerr << " at %s" << token.lexme;
  }
  std::cerr << msg << std::endl;
  m_parser.had_error = true;
}



}

